package com.lyon.dmeo.storage.client.raft.core;

import com.lyon.demo.storage.common.thread.ShutdownAble;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.SneakyThrows;
import org.slf4j.Logger;

import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author LeeYan9
 * @since 2022-05-10
 */
@SuppressWarnings("all")
@Data
@EqualsAndHashCode(callSuper = true)
public abstract class ShutdownAbleThread extends Thread implements ShutdownAble {

    private final AtomicBoolean running = new AtomicBoolean(true);

    private final ResettableCountDownLatch waitPoint = new ResettableCountDownLatch(1);

    private final AtomicBoolean hasNotify = new AtomicBoolean(false);

    private final CountDownLatch lastRunning = new CountDownLatch(1);

    protected final Logger logger;

    public ShutdownAbleThread(Logger logger) {
        this.logger = logger;
    }


    @Override
    public void run() {
        while (running.get()) {
            doWork();
        }
        lastRunning.countDown();
    }

    /**
     * 执行
     */
    protected abstract void doWork();


    /**
     * 唤醒
     */
    public void wakeup() {
        if (hasNotify.compareAndSet(false, true)) {
            waitPoint.countDown();
        }
    }

    /**
     * 阻塞，等待唤醒
     *
     * @param interval
     */
    @SneakyThrows
    public void waitForRunning(long interval) {
        if (hasNotify.compareAndSet(true, false)) {
            waitPoint.reset();
            try {
                waitPoint.await(interval, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                throw e;
            } finally {
                hasNotify.set(false);
            }
        }
    }

    @Override
    public void shutdown() {
        if (running.compareAndSet(true, false)) {
            try {
                // 唤醒线程执行任务
                wakeup();
                // 最多等待10s
                lastRunning.await(10, TimeUnit.SECONDS);
            } catch (Throwable e) {
                e.printStackTrace();
                if (Objects.nonNull(logger)) {
                    logger.error("关闭时发生异常", e);
                }
            }
            if (lastRunning.getCount() > 0) {
                if (Objects.nonNull(logger)) {
                    logger.warn("任务未执行完成,提前关闭");
                }
            }
        }
        doShutDown();
    }


    /**
     * 关闭服务
     */
    protected void doShutDown() {
    }
}
